import json
from urllib.request import Request

from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.db import connection
from django.http import (HttpRequest, HttpResponse, HttpResponseRedirect,
                         JsonResponse)
from drf_spectacular.utils import extend_schema
from rest_framework import status, viewsets
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView

from byxiaomi.models import FeedBack, Score, Student, Teacher
from byxiaomi.serializers import (APIGetTokenSerializer, FeedBackSerializer,
                                  MySerializer, ResAPIGetTokenSerializer,
                                  StudentSerializer, TeacherSerializer)


# 和ORM就不是关系很大了
def my_sql(sql):
    with connection.cursor() as cursor:
        cursor.execute(sql)
        row = cursor.fetchall()
    return row


# Create your views here.
@api_view(["get"])
def say_hello(request: Request):
    # html = "hello,my first view"
    data = {"code": 0, "msg": "hello"}

    return Response(data)


# 只能通过接口调用,为了学习服务端接收请求、返回响应以及使用ORM操作数据库的知识
def orm_submit(request: HttpRequest):
    if request.method == "POST":
        # 如果是表单参数
        if request.POST:
            # 1.检查评论内容是否填写,
            # 如果填写,则跳转到提交成功页面
            data = {}
            for k, v in request.POST.items():
                data[k] = v
            # 如果未填写,则刷新页面,继续让用户填写
            if data["text"] == "":
                return HttpResponseRedirect(
                    "http://127.0.0.1:8000/example/submit"
                )  # 这个提交评论的接口需要登录才能访问,所以说会重定向到登录页面
            # 如果用户已经填写,则跳转到提交成功的页面
            else:
                return HttpResponseRedirect(
                    "http://127.0.0.1:8000/example/result"
                )  # 这个评论成功的接口不需要登录就能访问,所以说可以正常返回
        # 如果是json参数
        elif request.body:
            request.json = json.loads(request.body)
            # 如果未填写,则刷新页面,继续让用户填写
            if request.json["text"] == "":
                return HttpResponseRedirect("http://127.0.0.1:8000/example/submit")
            else:
                # 接收到json参数,将数据保存到数据库中
                # 使用ORM来操作数据库
                # 1.将数据写入到数据库的方式一:实例化model
                # data = request.json
                #
                # obj = FeedBack()
                # obj.quality = data["quality"]
                # obj.attitude = data["attitude"]
                # obj.speed = data["speed"]
                # obj.text = data["text"]
                # obj.annoy = data["annoy"]
                # obj.save()

                # 2.将数据写入到数据库的方式二：调用类方法
                # FeedBack.objects.create(**data)

                # 3.查询数据：获取到id=1的数据(获取单条数据)
                # obj: FeedBack = FeedBack.objects.get(id=50)  # 没有记录或者是有多条数据都会报错
                # print(obj.text)

                # 4.查询数据：获取多条数据
                objs: [FeedBack] = FeedBack.objects.filter(speed=3)
                for obj in objs:
                    print(obj)  # FeedBack object (37)
                # print(objs.count())  # 查询出记录的条数(没有记录时为0)
                # print(objs.first())  # 查询出记录的第一条(没有记录时返回None)

                # 5.获取全部数据
                # obj_list = FeedBack.objects.all()
                # print(obj_list, type(obj_list))
                # print(list(obj_list)[-1])
                #
                # print(obj_list[2:4])  # 第三条和第四条记录
                # print([1, 2, 3, 4][2:4])  # 第三个和第四个元素

                # 6.条件查询
                # 等于
                # obj: FeedBack = FeedBack.objects.filter(id=30)
                # print(obj)
                # # 大于
                # obj_list = FeedBack.objects.filter(id__gt=30)
                # print(obj_list)
                # # 小于
                # obj_list = FeedBack.objects.filter(id__lt=30)
                # print(obj_list)
                # # 大于等于
                # obj_list = FeedBack.objects.filter(id__gte=30)
                # print(obj_list)
                # # 小于等于
                # obj_list = FeedBack.objects.filter(id__lte=30)
                # print(obj_list)
                # # 包含
                # obj_list = FeedBack.objects.filter(id__in=[2, 3, 19, 111])
                # print(obj_list)
                # # 不等于(所有的去掉包含的)
                # obj_list = FeedBack.objects.all().exclude(id__in=[2, 3, 19, 111])
                # print(obj_list)

                # 7.修改数据(修改数据的前提是查询到数据然后进行操作)
                # obj = FeedBack.objects.get(id=1)
                # print(f"修改之前的评论内容是：{obj.text}")
                # # 修改数据并入库
                # obj.text = "修改数据......12345678"
                # obj.save()
                # print(f"修改之后的评论内容是：{obj.text}")

                # 又踩了一个坑.......
                # obj_list = FeedBack.objects.filter(id=30)
                # obj = obj_list.first()
                # # print(f"修改之前的评论内容是：{obj_list.first().text}")  # A对象
                # print(f"修改之前的评论内容是：{obj.text}")  # A对象
                # # 修改数据并入库
                # # obj_list.first().text = "修改数据......87654321"  # B对象：修改了但是没保存
                # obj.text = "修改数据......87654321"  # A对象
                # # obj_list.first().save()  # C对象：保存了但是没修改
                # obj.save()  # A对象
                # # print(f"修改之后的评论内容是：{obj_list.first().text}")  # D对象
                # print(f"修改之后的评论内容是：{obj.text}")  # A对象

                # 修改数据
                # obj_list = FeedBack.objects.filter(id__gte=50)
                # for obj in obj_list:
                #     print(f"修改之前的评论内容是：{obj.text}")
                #     # 修改数据并入库
                #     obj.text = "88888888"
                #     obj.save()
                #     print(f"修改之后的评论内容是：{obj.text}")

                # 8.删除数据
                # 方式1：删除实例对象
                # 先查询到你要删除的数据,再进行删除操作
                # obj_list = FeedBack.objects.filter(id__in=[30, 31])
                # # 删除之后,查看所有的记录
                # obj_list: list[FeedBack] = FeedBack.objects.all()
                # for obj in obj_list:  # 执行了SQL
                #     print(f"{obj=}")
                # obj_list[0].delete()  # 执行SQL了

                # print(FeedBack.objects.filter(id=125).exists())  # False

                # 方式2：调用类方法
                # 本质上是和上面的是一样的.
                # FeedBack.objects.filter(id__in=[11, 12]).delete()
                # 删除之后,查看所有的记录
                # obj_list: list[FeedBack] = FeedBack.objects.all()
                # for obj in obj_list:  # 使用缓存数据,未执行SQL
                #     print(f"{obj=}")

                """
                # 惰性求值
                obj_list = FeedBack.objects.all()
                print(f"{obj_list=}", f"{type(obj_list)=}")
                print("----------------------------------------")

                # list(obj_list)  # 没有执行SQL
                print(obj_list)  # 没有执行SQL
                data = {
                    "quality": 5,
                    "attitude": 2,
                    "speed": 4,
                    "text": "hahahah",
                    "annoy": False,
                }
                print("============================")
                obj_list.create(**data)  # 执行了SQL

                list(obj_list)  # 没有执行SQL
                print(obj_list)  # 没有执行SQL

                print(FeedBack.objects.filter(id=28).exists())  # 执行了SQL
                """

                # 9.显示sql
                # data = request.json
                # FeedBack.objects.create(**data)
                #
                # obj_list = FeedBack.objects.all()
                # print(f"sql={obj_list.query}")

                # # 10. 执行sql
                # sql = """
                # INSERT INTO "main"."byxiaomi_feedback" ("quality","attitude","speed","text","annoy","user_id") VALUES ('2','3','2','222','1','3');
                # """
                # res = my_sql(sql)
                # print(res)
                return JsonResponse(request.json)

    elif request.method == "GET":
        with open("html/submit.html", encoding="utf-8") as f:
            content = f.read()
        html = content
        return HttpResponse(html)


def register(request):
    if request.method == "POST":
        data = json.loads(request.body)
        # 1.校验email、username、password、confirm_pass是否为空
        keys_list = ["email", "username", "password", "confirm_password"]
        for key in keys_list:
            if not data[key]:  # 如果为空
                return JsonResponse(
                    {"code": -1, "msg": f"{key} 不能为空......"}, status=422
                )
        # 2.校验密码与确认密码是否一致
        if data["password"] != data["confirm_password"]:
            return JsonResponse(
                {"code": -2, "msg": "两次输入的密码不一致......"}, status=422
            )

        # 3.密码复杂性校验:不能少于6位
        if len(data["password"]) < 6:
            return JsonResponse(
                {"code": -3, "msg": "密码长度不能小于6位......"}, status=422
            )

        # 4.用户是否已经注册的校验
        # 先去数据库中查询是否有这个用户
        user_list = User.objects.filter(username=data["username"])
        if user_list:
            return JsonResponse(
                {"code": -4, "msg": f"{data['username']},该用户已存在......"},
                status=400,
            )

        # 注册账号
        new_user = User.objects.create_user(
            username=data["username"], email=data["email"], password=data["password"]
        )

        # 注册账号之后,自动登录
        login(request, new_user)

        return JsonResponse({"code": 0, "msg": f"{data['username']}注册成功!"})

    with open("html/register.html", encoding="utf-8") as f:
        content = f.read()

    return HttpResponse(content)


def register_success(request):
    with open("html/register_success.html", encoding="utf-8") as f:
        content = f.read()
    html = content
    return HttpResponse(html)


@login_required()  # login_required装饰器
def submit(request):
    """
    1.禁止匿名访问(自己写代码实现的)
    # 判断是否登录：request.user.is_authenticated为True表示已登录
    if not request.user.is_authenticated:
        return HttpResponse("请登录后再发布......")
    """

    if request.method == "POST":
        # 如果是表单参数
        if request.POST:
            # 1.检查评论内容是否填写,
            # 如果填写,则跳转到提交成功页面
            data = {}
            for k, v in request.POST.items():
                # 是否提交的值,表单提交时,'annoy': ['true']
                if v == "true":
                    v = True
                elif v == "false":
                    v = False
                data[k] = v
            # 如果未填写评论内容,则刷新页面,继续让用户填写
            if data["text"] == "":
                return HttpResponseRedirect("http://127.0.0.1:8000/submit")
            # 如果用户已经填写评论内容,则跳转到提交成功的页面
            else:
                # 将用户提交的数据保存到数据库中
                FeedBack.objects.create(**data)
                return HttpResponseRedirect("http://127.0.0.1:8000/result")
        # 如果是json参数
        if request.body:
            data = json.loads(request.body)
            print(f"{data=}")
            # 如果未填写,则刷新页面,继续让用户填写
            if data["text"] == "":
                return HttpResponseRedirect("http://127.0.0.1:8000/submit")
            else:
                # 方式1：查询该用户是否存在评论
                # user_list = FeedBack.objects.filter(user=request.user)
                # 方式2：用该用户的feedback_set.all方法检查是否有该用户的评论记录
                user_list = request.user.feedback_set.all()
                if user_list:  # 如果存在评论
                    return JsonResponse(
                        {"code": -1, "msg": "该用户已经评论过了......"}, status=400
                    )

                # 接收到前端传递进来的json格式的数据
                # 方式1：保存评论
                # FeedBack.objects.create(
                #     quality=data["quality"],
                #     attitude=data["attitude"],
                #     speed=data["speed"],
                #     text=data["text"],
                #     annoy=data["annoy"],
                #     user=request.user
                # )

                # 方式2：保存评论
                obj = FeedBack()
                obj.quality = data["quality"]
                obj.attitude = data["attitude"]
                obj.speed = data["speed"]
                obj.text = data["text"]
                obj.annoy = data["annoy"]
                obj.user = request.user

                obj.save()  # 注意不要忘记入库!!!!!!
                # 如果使用HttpResponse来生成响应的结果的话
                # res_data = {"code": 0, "msg": "评论保存成功", "data": data}
                # res_data_str = json.dumps(res_data)
                # res = HttpResponse(res_data_str)
                # res.headers["content-Type"] = "application/json"
                # return res
                return JsonResponse({"code": 0, "msg": "评论保存成功", "data": data})

    elif request.method == "GET":
        with open("html/submit.html", encoding="utf-8") as f:
            content = f.read()
        html = content
        return HttpResponse(html)


def result(request):
    with open("html/result.html", encoding="utf-8") as f:
        content = f.read()
    html = content
    return HttpResponse(html)


def get_request_info(request):
    ip = request.META.get("HTTP_X_FORWARDED_FOR", request.META["REMOTE_ADDR"])
    html = f"""
    接收到的请求：
        请求行：
            请求方法: {request.method}
            请求路径：{request.path}
            查询参数：{request.GET}
        请求头：{request.headers}
        Cookie: {request.COOKIES}
        
        请求正文: {request.body}
        
        请求ip: {ip}
        
        当前用户: {request.user}
        Session数据: 
            {request.session},
            {request.session.get("name", "xiaomi")}
        
        
    """

    return HttpResponse(html)


def info_method(request):
    html = request.method

    return HttpResponse(html)


def info_path(request):
    html = request.path

    return HttpResponse(html)


def info_get(request):
    print(request.GET)  # <QueryDict: {'a': ['1'], 'b': ['2'], 'c': ['3', '4', '5']}>
    data = {}
    for k, v in request.GET.items():
        data[k] = v

    html = json.dumps(data)

    return HttpResponse(html)


def info_post(request):
    print(request.POST)
    data = {}
    for k, v in request.POST.items():
        data[k] = v

    html = json.dumps(data)

    return HttpResponse(html)


def info_json(request):
    print(request.body)  # b'{"a": "\\u9648\\u9526\\u5cf0", "b": 1, "c": 2}'
    data = json.loads(request.body)
    print(data, type(data))  # {'a': '陈锦峰', 'b': 1, 'c': 2} <class 'dict'>

    html = json.dumps(data)
    print(html, type(html))  # {"a": "\u9648\u9526\u5cf0", "b": 1, "c": 2} <class 'str'>

    # return HttpResponse(html)
    return JsonResponse(data)


def info_cookie(request):
    data = {}
    for k, v in request.COOKIES.items():
        data[k] = v

    html = json.dumps(data)

    return HttpResponse(html)


def info_session(request):
    num = request.session.get("num", 0)
    num += 1
    request.session["num"] = num

    data = {"num": request.session["num"]}

    html = json.dumps(data)

    return HttpResponse(html)


def info_res(request):
    pass

    # 响应状态码
    # return HttpResponse(html, status=HttpResponseNotFound.status_code)
    # return HttpResponseNotFound(html)

    # 响应头
    # return HttpResponseNotFound(html, headers={"name": "xiaomi", "age": "32"})
    # cookie信息是在请求头里面的,可以在请求头里面设置(但是一般不会这么做)
    # return HttpResponseNotFound(html, headers={
    #     'Set-Cookie': 'name=xiaomi;sessionid=5n8cs67cj6kp2uij0zc6ianvw30vtsg9; expires=Thu, 03 Aug 2023 01:37:17 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax'})

    # cookie信息
    # resp = HttpResponseNotFound(html)
    #
    # resp.set_cookie("name", "xiaomi")
    # resp.set_cookie("salary", "25K")

    # 重定向
    # return HttpResponseRedirect("http://www.baidu.com")

    # json响应的第一种实现方式
    # 1.将内容转化成json字符串
    # data = {"name": "小蜜", "age": 32}
    # # 2.将json字符串作为响应正文
    # data_str = json.dumps(data)
    # # 3.将json作为响应头
    # return HttpResponse(data_str, headers={"Content-Type": "application/json"})

    # json响应的第二种实现方式
    data = {"name": "小蜜", "age": 32}
    return JsonResponse(data)


def create_sql_data(request):
    data = json.loads(request.body)

    Score.objects.create(**data)

    return JsonResponse(data)


# 函数实现使用DRF开发的一个极简版本的接口(没有数据库,没有定义接口的格式)
@extend_schema(
    request={"application/json": {}, "application/x-www-form-urlencoded": {}},
    responses={(200, "application/json"): {}},
    description="接收任意表单或JSON数据，并原样返回。",
)
@api_view(["post", "get"])
def drf_show(request):
    data = request.data
    print(f"{data=}")
    print(
        f"{data=}, {type(data)=}",
    )
    return Response(data)


# 类实现使用DRF开发的一个极简版本的接口(没有数据库,有定义接口的格式)
# APIView: 构建单个API视图
@extend_schema(
    request={
        "application/json": MySerializer,
        "application/x-www-form-urlencoded": MySerializer,
    },
)
class MyView(APIView):
    def post(self, request):
        serializer = MySerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            print(data)
            return Response({"code": 0, "method": "post", "data": data})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def get(self, request):
        serializer = MySerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            print(f"{data=}")
            return Response({"code": 0, "method": "get", "data": data})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request):
        serializer = MySerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            print(data)
            return Response({"code": 0, "method": "put", "data": data})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request):
        serializer = MySerializer(data=request.data)
        if serializer.is_valid():
            data = serializer.data
            print(data)
            return Response({"code": 0, "method": "delete", "data": data})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class StudentsViewSets(viewsets.ModelViewSet):
    # 视图集里面的Model视图集合：处理Model/使用Model
    queryset = Student.objects.all()  # 数据来源
    serializer_class = StudentSerializer  # 数据格式


class TeachersViewSets(viewsets.ModelViewSet):
    # 视图集里面的Model视图集合：处理Model/使用Model
    queryset = Teacher.objects.all()  # 数据来源
    serializer_class = TeacherSerializer  # 数据格式


# 如果使用DRF开发需要使用数据库的接口
# ViewSets: 构建一组相关的 API 视图
class FeedBackViewSets(
    viewsets.ModelViewSet
):  # 视图集里面的Model视图集合：处理Model/使用Model
    queryset = FeedBack.objects.all()  # 数据来源
    serializer_class = FeedBackSerializer  # 数据格式

    # permission_classes = [permissions.AllowAny]

    # 上面两行代码就可以实现使用接口对数据进行增删查改
    # http://127.0.0.1:8000/feedback/
    # http://127.0.0.1:8000/feedback/{pk}

    # 也可以自己自定义接口实现具体的业务功能
    @action(
        [
            "GET",
            "POST",
        ],
        detail=False,
    )
    def ret_info(self, request):
        data = request.data
        method = request.method
        params = request.query_params

        res_data = {"code": 0, "method": method, "data": data, "params": params}
        return Response(res_data)


from rest_framework.authtoken.models import Token
from rest_framework.request import Request


@extend_schema(
    request={"application/json": APIGetTokenSerializer},
    responses={200: ResAPIGetTokenSerializer},
)
@api_view(["post"])
@permission_classes([AllowAny])
def api_get_token(request: Request):
    data: dict = request.data

    username = data.get("username")
    password = data.get("password")

    try:
        # 根据用户传递的用户名在数据库中找到对应的用户
        user: User = User.objects.get(username=username)
    except:
        return Response({"code": -1, "msg": "该账号不存在......", "token": ""})
    # 检查密码是否正确
    is_user = user.check_password(password)
    # 也可以直接使用authenticate来判断账号密码是否正确
    # user = authenticate(username=username, password=password)

    if is_user:
        # user用户获取或者创建一个token
        token, is_create = Token.objects.get_or_create(user=user)
        return Response({"code": 0, "msg": "登录成功", "token": token.key})
    else:
        return Response({"code": 0, "msg": "密码错误......", "token": ""})
